package com.yq.testmodule.second_floor;

import static android.view.MotionEvent.obtain;
import static com.scwang.smart.refresh.layout.util.SmartUtil.isTransformedTouchPointInView;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.webkit.WebView;
import android.widget.AbsListView;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingParent;
import androidx.core.view.ScrollingView;
import androidx.viewpager.widget.ViewPager;


import com.scwang.smart.refresh.layout.SmartRefreshLayout;
import com.scwang.smart.refresh.layout.api.RefreshComponent;
import com.scwang.smart.refresh.layout.constant.RefreshState;
import com.yq.testmodule.R;

import net.lucode.hackware.magicindicator.buildins.UIUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 待做事项：
 * 1. 横向不弹出二楼 (完成）
 * 2， 竖向滑动（内部view先滑动）
 */
public class MySecondFloorView extends ConstraintLayout {

    //<editor-fold desc="初始化及变量">
    public MySecondFloorView(@NonNull Context context) {
        super(context);
        init();
    }

    public MySecondFloorView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MySecondFloorView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public MySecondFloorView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }


    private void init() {
        ViewConfiguration configuration = ViewConfiguration.get(getContext());
        mTouchSlop = configuration.getScaledTouchSlop();
    }

    ConstraintLayout mClFloor;
    TextView tvRefresh;

    View mContentView;//临时id写死获取，后续可优化

    public void setInitPosition(int position) {
        initPosition = position;
        refreshPosition = initPosition + UIUtil.dip2px(getContext(), (double) gap / 2);
        secondRefreshPosition = refreshPosition + UIUtil.dip2px(getContext(), gap);
        post(() -> {
            mClFloor.setTranslationY(initPosition);
        });

    }

    int gap = 80;

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mContentView = getViewById(R.id.cl_content);
        initPosition = UIUtil.dip2px(getContext(), 0);
        refreshPosition = initPosition + UIUtil.dip2px(getContext(), gap);
        secondRefreshPosition = refreshPosition + UIUtil.dip2px(getContext(), gap);
        mClFloor = (ConstraintLayout) getViewById(R.id.cl_floor);
        tvRefresh = mClFloor.findViewById(R.id.tv_fresh);

        post(() -> {
            LayoutParams mClFloorLayoutParams = (LayoutParams) mClFloor.getLayoutParams();
            mClFloorLayoutParams.height = getMeasuredHeight();
            mClFloor.setLayoutParams(mClFloorLayoutParams);
            mClFloor.setTranslationY(initPosition);
        });

        tvRefresh.setOnClickListener(v -> hideFloor());
    }

    //    float dx, dy;//记录滑动过程中的偏移量（距离按下的位置）
    float downX = 0, downY = 0; //记录down按下的位置

    float dragRate = 1f;//拖拽阻尼

    int state = 0;
    static int STATE_HIDE = 0;//隐藏状态
    static int STATE_PULLING = 1;//下拉中
    static int STATE_RELEASE_TO_REFRESH = 2;//释放去刷新状态
    static int STATE_REFRESH = 3;//刷新状态
    static int STATE_RELEASE_TO_ENTRY_FLOOR = 4;//释放进入二楼状态
    static int STATE_SECOND_FLOOR = 5;//进入二楼状态


    public int initPosition;//二楼 初始显示的位置
    int refreshPosition;//开始刷新的距离
    int secondRefreshPosition;//进入二楼的距离

    protected int mTouchSlop;
    protected View mScrollableView;


    boolean mSuperDispatchTouchEvent;
    boolean isChildDeal = false;


    float spinner = 0;//最终需要移动的距离
    protected boolean mIsBeingDragged;//是否正在拖动


    MotionEvent mFalsifyEvent;

    private boolean disableSecondFloor = true;

    protected int mLastSpinner;//最后的，的Spinner
    //</editor-fold>


    public void setDisableSecondFloor(boolean disableSecondFloor) {
        this.disableSecondFloor = disableSecondFloor;
    }

    protected float mTouchY = 0f;
    protected float mTouchX;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
//        if(!ConfigCenter.INSTANCE.getShowSecondFloor()||disableSecondFloor){
//            return super.dispatchTouchEvent(ev);
//        }
        if (state == STATE_SECOND_FLOOR) {
            return super.dispatchTouchEvent(ev);
        }
        float touchY = ev.getY();
        float touchX = ev.getX();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = ev.getX();
                downY = ev.getY();
                mTouchY = ev.getY();
                mTouchX = ev.getX();
                mIsBeingDragged = false;
                onActionDown(ev);
                mSuperDispatchTouchEvent = super.dispatchTouchEvent(ev);
                mFalsifyEvent = null;
                return true;

            case MotionEvent.ACTION_MOVE:

                float dx = touchX - mTouchX;
                float dy = touchY - mTouchY;

                //未被拖动时
                if (!mIsBeingDragged) {
//                    log("达到最小滑动判定： " + (Math.abs(dy) >= mTouchSlop)
//                            + " isChild Deal: " + isChildDeal
//                            + " dy > dx: " + (Math.abs(dx) < Math.abs(dy))
//                            + " state: " + state
//                            + "  dy = " + dy);

                    if ((Math.abs(dy) >= mTouchSlop) && Math.abs(dx) < Math.abs(dy)) {
                        if (dy > 0 && canRefresh(mScrollableView,mActionEvent)) {
                            mIsBeingDragged = true;
                            mTouchY = touchY - mTouchSlop;//调整 mTouchSlop 偏差
                        }
                        if (mIsBeingDragged) {
                            dy = touchY - mTouchY;//调整 mTouchSlop 偏差 重新计算 dy
                            if (mSuperDispatchTouchEvent) {//如果父类拦截了事件，发送一个取消事件通知
                                ev.setAction(MotionEvent.ACTION_CANCEL);
                                super.dispatchTouchEvent(ev);
                            }
                            state = STATE_PULLING;
                            final ViewParent parent = getParent();
                            if (parent instanceof ViewGroup) {
                                ((ViewGroup) parent).requestDisallowInterceptTouchEvent(true);//通知父控件不要拦截事件
                            }
                        }
                    }
                }

                if (mIsBeingDragged) {

                    int spinner = (int) dy;

                    if (spinner <= 0) {
                        log("拖拽过程中，主动滚动内容");
                        mLastSpinner = spinner;
                        long time = ev.getEventTime();
                        if (mFalsifyEvent == null) {
                            mFalsifyEvent = obtain(time, time, MotionEvent.ACTION_DOWN, mTouchX + dx, mTouchY, 0);
                            super.dispatchTouchEvent(mFalsifyEvent);
                        }
                        MotionEvent em = obtain(time, time, MotionEvent.ACTION_MOVE, mTouchX + dx, mTouchY + spinner, 0);
                        super.dispatchTouchEvent(em);
                        em.recycle();
                    }

                    moveSpinnerInfinitely(spinner);
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:

                if (mFalsifyEvent != null) {
                    mFalsifyEvent.recycle();
                    mFalsifyEvent = null;
                    long time = ev.getEventTime();
                    MotionEvent ec = obtain(time, time, ev.getAction(), mTouchX, touchY, 0);
                    super.dispatchTouchEvent(ec);
                    ec.recycle();
                }

                boolean canDispatchChild = true;
                if (state != STATE_HIDE || mIsBeingDragged) {
                    canDispatchChild = false;
                }
                reset();
                float translationY = mClFloor.getTranslationY();
                if (translationY > refreshPosition && translationY < secondRefreshPosition) {
                    changeToRefreshState();
                } else if (translationY > secondRefreshPosition) {
                    changeToSecondState();
                } else {
                    hideFloor();
                }
                changeDrageRate();
                if (mIsBeingDragged) {
                    mIsBeingDragged = false;//关闭拖动状态
                    return true;
                }
                if (!canDispatchChild) {
                    return true;
                }
                break;
        }

//        log("子view 兜底处理： " + ev.getY());
        return super.dispatchTouchEvent(ev);
    }


    /**
     * 黏性移动 spinner
     * @param spinner 整个手势滚动的距离（从down开始）
     */
    private void moveSpinnerInfinitely(int spinner) {

        final double M =(secondRefreshPosition - initPosition) * 2;
        final double H = Math.max(getResources().getDisplayMetrics().heightPixels / 2,  getHeight());
        final double x = Math.max(0, spinner * .5f);
        double y = M * (1 - Math.pow(100, -x / (H == 0 ? 1 : H)));// 公式 y = M(1-100^(-x/H))



        if(y < 0 ){
            log("y  =  " + y);
            mClFloor.setTranslationY(initPosition);
            state = STATE_HIDE;
            for (ScrollerDistanceListener listener : listeners) {
                listener.scroller(0);
            }
            return;
        }
//        y = spinner * dragRate;
        log("spinner = "+spinner+ " y = "+y );

        float translationY = (float) (initPosition + y);
        mClFloor.setTranslationY(translationY);
        dealMovingState(translationY);

        for (ScrollerDistanceListener listener : listeners) {
            listener.scroller(translationY - initPosition);
        }
    }


    //1227.9827
    private void dealMovingState(float translationY) {
        if (translationY > refreshPosition && translationY < secondRefreshPosition) {
            tvRefresh.setText("释放刷新");
            state = STATE_RELEASE_TO_REFRESH;
        } else if (translationY > secondRefreshPosition) {
            state = STATE_RELEASE_TO_ENTRY_FLOOR;
            tvRefresh.setText("释放进入二楼");
        } else if (translationY < refreshPosition && translationY >= initPosition) {
            tvRefresh.setText("下拉刷新");
            state = STATE_PULLING;
        } else {
            tvRefresh.setText("下拉刷新");
        }
        changeDrageRate();
    }

    public PointF mActionEvent;

    private void onActionDown(MotionEvent e) {
        PointF point = new PointF(e.getX(), e.getY());
        point.offset(-mContentView.getLeft(), -mContentView.getTop());
        if (mScrollableView != mContentView) {
            //如果内容视图不是 ScrollableView 说明使用了Layout嵌套内容，需要动态搜索 ScrollableView
            mScrollableView = findScrollableViewByPoint(mContentView, point, mScrollableView);
        }

        if (mScrollableView == mContentView) {
            //如果内容视图就是 ScrollableView 就不需要使用事件来动态搜索 而浪费CPU时间和性能了
            mActionEvent = null;
        } else {
            mActionEvent = point;
        }
    }

    //<editor-fold desc="更改状态">


    private void reset() {
        mIsBeingDragged = false;
        mScrollableView = null;
        isChildDeal = false;
    }

    private void changeDrageRate() {
        if (state == STATE_RELEASE_TO_REFRESH) {
            dragRate = 0.5f;
        } else if (state == STATE_RELEASE_TO_ENTRY_FLOOR) {
            dragRate = 0.2f;
        } else {
            dragRate = 1f;
        }
//        log("dragRate: "+dragRate);
    }


    private void hideFloor() {
        animalToDes(initPosition);
        state = STATE_HIDE;
        tvRefresh.setText("下拉刷新");
    }

    private void changeToRefreshState() {
        //移动到刷新位置
        animalToDes(refreshPosition);
        state = STATE_REFRESH;
        tvRefresh.setText("刷新中...");
        if (mRefreshListener != null) {
            mRefreshListener.onRefresh(this);
        }

        postDelayed(new Runnable() {
            @Override
            public void run() {
                hideFloor();
            }
        }, 1000);
    }


    private void changeToSecondState() {
        animalToDes(mClFloor.getHeight());
        state = STATE_SECOND_FLOOR;
    }


    private void animalToDes(float desPosition) {
        ObjectAnimator translationY = ObjectAnimator.ofFloat(mClFloor, "translationY", desPosition);
        translationY.setDuration(200);
        translationY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                float y = mClFloor.getTranslationY();
                for (ScrollerDistanceListener listener : listeners) {
                    listener.scroller(y - initPosition);
                }
            }
        });
        translationY.start();
    }

    List<ScrollerDistanceListener> listeners = new ArrayList<>();

    public void addScrollerListener(ScrollerDistanceListener s) {
        if (listeners.contains(s)) {
            return;
        }
        listeners.add(s);
    }

    public void removeScrollerListener(ScrollerDistanceListener s) {
        listeners.remove(s);
    }


    @Override
    protected void detachAllViewsFromParent() {
        super.detachAllViewsFromParent();
        listeners.clear();
    }


    public interface ScrollerDistanceListener {
        void scroller(float dy);
    }
    //</editor-fold>

    protected View findScrollableViewByPoint(View content, PointF event, View orgScrollableView) {
        if (content instanceof ViewGroup && event != null) {
            ViewGroup viewGroup = (ViewGroup) content;
            final int childCount = viewGroup.getChildCount();
            PointF point = new PointF();
            for (int i = childCount; i > 0; i--) {
                View child = viewGroup.getChildAt(i - 1);
                if (isTransformedTouchPointInView(viewGroup, child, event.x, event.y, point)) {
                    if (child instanceof ViewPager || !isContentView(child)) {
                        event.offset(point.x, point.y);
                        child = findScrollableViewByPoint(child, event, orgScrollableView);
                        event.offset(-point.x, -point.y);
                    }
                    return child;
                }
            }
        }
        return orgScrollableView;
    }

    public static boolean isContentView(View view) {
//        if (view instanceof RefreshComponent) {
//            return false;
//        }
        if (view instanceof SmartRefreshLayout) {
            return false;
        }
        return isScrollableView(view)
                || view instanceof ViewPager
                || view instanceof NestedScrollingParent;
    }


    public static boolean isScrollableView(View view) {
        return view instanceof AbsListView
                || view instanceof ScrollView
                || view instanceof ScrollingView
                || view instanceof WebView
                || view instanceof NestedScrollingChild;
    }

    /**
     * 判断内容是否可以刷新
     *

     * @return 是否可以刷新
     */
    public   boolean canRefresh(View targetView, PointF touch) {
        if(targetView == null){
            return true;
        }
        if (targetView.canScrollVertically(-1) && targetView.getVisibility() == View.VISIBLE) {
            return false;
        }
        //touch == null 时 canRefresh 不会动态递归搜索
        if (targetView instanceof ViewGroup && touch != null) {
            ViewGroup viewGroup = (ViewGroup) targetView;
            final int childCount = viewGroup.getChildCount();
            PointF point = new PointF();
            for (int i = childCount; i > 0; i--) {
                View child = viewGroup.getChildAt(i - 1);
                if (isTransformedTouchPointInView(viewGroup, child, touch.x, touch.y, point)) {
                    Object tag = child.getTag(com.scwang.smart.refresh.layout.kernel.R.id.srl_tag);
                    if ("fixed".equals(tag) || "fixed-bottom".equals(tag)) {
                        return false;
                    }
                    touch.offset(point.x, point.y);
                    boolean can = canRefresh(child, touch);
                    touch.offset(-point.x, -point.y);
                    return can;
                }
            }
        }
        return true;
    }


    private void log(String content) {
        Log.e("YYYY", content);
    }


    public void finishRefresh() {
        hideFloor();
    }

    public void refreshFail() {
        hideFloor();
    }

    private OnRefreshListener mRefreshListener;

    public void setOnRefreshListener(OnRefreshListener listener) {
        this.mRefreshListener = listener;
    }

    public interface OnRefreshListener {
        void onRefresh(@NonNull MySecondFloorView secondFloorView);
    }

    public void autoRefresh() {

    }
}
